// 柯里化（Currying）是把接受多个参数的函数变换成接受一个单一参数（最初函数的第一个参数）的函数
// 并且返回接受余下的参数且返回结果的新函数
// 实现思路：利用闭包的原理，
    // 先把函数和参数缓存起来，并返回一个能接收剩余参数的函数
    // 继续调用，如果参数个数不够则继续递归
    // 当参数的个数满足函数预接收的个数，执行函数，返回结果


function toCurry(func, ...args) {
    // 需要柯里化的函数作为参数
    return function() {
        // 合并参数
        args = [...args, ...arguments];
        // 判断函数数量是否足够
        if (args.length < func.length) {
            // 不够继续递归
            // 注意这里每一次递归都会形成新的闭包
            // 保证柯里化函数每一步都是独立的 互不影响
            return toCurry(func, ...args);
        } else {
            // 参数足够了就执行函数
            return func.apply(null, args);
        };
    };
};


const add = function(a, b, c) {
    return a + b + c;
};


const f = toCurry(add);  // 这里add就是需要柯里化的函数

console.log(f(1)(2)(3));



/*
    柯里化的优点：
    1. 延迟计算
    2. 动态创建函数
    3. 参数复用
*/

//-----------------------------------------------------------------------------------------------------------------------------------------
// 1. 延迟计算

// 2. 动态创建函数
const addEvent = (function () {
    if (window.addEventListener) {
        return (elem, type, fn, capture) => {
            elem.addEventListener(type, (e) => fn.call(elem, e), capture);
        };
    } else {
        return (elem, type, fn, capture) => {
            elem.attachEvent('on' + type, (e) => fn.call(elem, e));
        };
    }
})();

// 3. 参数复用
const obj = { name: 'test' };
const foo = function (prefix, suffix) {
    console.log(prefix + this.name + suffix);
}.bind(obj, 'currying-');

foo('-function'); // currying-test-function